import Foundation
import CoreML
import Accelerate

// MARK: - 实时咀嚼检测器

final class RealtimeChewingDetector: ObservableObject {
    
    // MARK: - 发布属性
    
    /// 是否检测到咀嚼
    @Published var isChewing: Bool = false
    
    /// 咀嚼概率 (0-1)
    @Published var chewingProbability: Double = 0.0
    
    /// 缓冲区填充百分比
    @Published var bufferFilled: Int = 0
    
    /// 检测状态文本
    @Published var statusText: String = "等待数据..."
    
    /// 总预测次数
    @Published var predictionCount: Int = 0
    
    /// 咀嚼动作计数（每咀嚼一下+1）
    @Published var chewingActionCount: Int = 0
    
    /// 咀嚼次数统计（弃用，保留兼容性）
    @Published var chewingDetectedCount: Int = 0
    
    // MARK: - 私有属性
    
    private let model: MLModel
    private let sampleRate: Int = 25  // Hz - 匹配训练时的采样率
    private let windowSize: Int = 64  // 样本数 (2.56秒@25Hz)
    private let hopSize: Int = 5       // 步长 (0.2秒, 接近实时检测)
    
    // 状态跟踪（用于检测咀嚼动作）
    private var previousChewingState: Bool = false
    
    // 双阈值（滞后比较器，避免抖动）
    private let upperThreshold: Double = 0.6  // 进入咀嚼状态的阈值
    private let lowerThreshold: Double = 0.4  // 退出咀嚼状态的阈值
    
    // Madgwick姿态估计
    private var quaternion: [Double] = [1.0, 0.0, 0.0, 0.0]  // w, x, y, z
    private let beta: Double = 0.1
    
    // 滑动窗口缓冲区
    private var bufferAx: [Double] = []
    private var bufferAy: [Double] = []
    private var bufferAz: [Double] = []
    
    // 样本计数
    private var sampleCount: Int = 0
    
    // MFCC特征提取器
    private let mfccExtractor = MFCCExtractor()
    
    // MARK: - 初始化
    
    init?(modelURL: URL) {
        do {
            // 加载CoreML模型
            let config = MLModelConfiguration()
            config.computeUnits = .cpuAndGPU
            self.model = try MLModel(contentsOf: modelURL, configuration: config)
            
            print("✅ [检测器] 模型加载成功")
        } catch {
            print("❌ [检测器] 模型加载失败: \(error)")
            return nil
        }
    }
    
    // MARK: - 主要方法
    
    /// 处理单个IMU样本
    func processSample(ax: Double, ay: Double, az: Double,
                      wx: Double, wy: Double, wz: Double) {
        // 直接使用传入的线性加速度（AirPods已经去除重力）
        // 调试：打印前几次的详细信息
        if sampleCount < 5 {
            print("🔬 [样本\(sampleCount)] 线性加速度: ax=\(String(format: "%.3f", ax)), ay=\(String(format: "%.3f", ay)), az=\(String(format: "%.3f", az))")
            print("🔬 [样本\(sampleCount)] 陀螺仪: wx=\(String(format: "%.3f", wx)), wy=\(String(format: "%.3f", wy)), wz=\(String(format: "%.3f", wz))")
        }
        
        // 添加到缓冲区
        bufferAx.append(ax)
        bufferAy.append(ay)
        bufferAz.append(az)
        
        // 保持窗口大小
        if bufferAx.count > windowSize {
            bufferAx.removeFirst()
            bufferAy.removeFirst()
            bufferAz.removeFirst()
        }
        
        sampleCount += 1
        
        // 更新缓冲区百分比
        DispatchQueue.main.async {
            self.bufferFilled = Int(Double(self.bufferAx.count) / Double(self.windowSize) * 100)
        }
        
        // 5. 检查是否可以预测（缓冲区满后每5个样本预测一次）
        if bufferAx.count == windowSize && sampleCount % hopSize == 0 {
            predict()
        }
    }
    
    /// 重置检测器
    func reset() {
        bufferAx.removeAll()
        bufferAy.removeAll()
        bufferAz.removeAll()
        quaternion = [1.0, 0.0, 0.0, 0.0]
        sampleCount = 0
        previousChewingState = false
        
        DispatchQueue.main.async {
            self.isChewing = false
            self.chewingProbability = 0.0
            self.bufferFilled = 0
            self.statusText = "已重置"
            self.predictionCount = 0
            self.chewingDetectedCount = 0
            self.chewingActionCount = 0
        }
    }
    
    // MARK: - 私有方法
    
    /// Madgwick姿态更新
    private func updateQuaternion(gx: Double, gy: Double, gz: Double,
                                 ax: Double, ay: Double, az: Double) {
        let dt = 1.0 / Double(sampleRate)
        
        var q0 = quaternion[0]
        var q1 = quaternion[1]
        var q2 = quaternion[2]
        var q3 = quaternion[3]
        
        // 归一化加速度
        let norm = sqrt(ax*ax + ay*ay + az*az)
        guard norm > 0 else { return }
        let ax_norm = ax / norm
        let ay_norm = ay / norm
        let az_norm = az / norm
        
        // 梯度下降
        let _2q0 = 2.0 * q0
        let _2q1 = 2.0 * q1
        let _2q2 = 2.0 * q2
        let _2q3 = 2.0 * q3
        let _4q0 = 4.0 * q0
        let _4q1 = 4.0 * q1
        let _4q2 = 4.0 * q2
        let _8q1 = 8.0 * q1
        let _8q2 = 8.0 * q2
        let q0q0 = q0 * q0
        let q1q1 = q1 * q1
        let q2q2 = q2 * q2
        let q3q3 = q3 * q3
        
        // 梯度
        var s0 = _4q0 * q2q2 + _2q2 * ax_norm + _4q0 * q1q1 - _2q1 * ay_norm
        var s1 = _4q1 * q3q3 - _2q3 * ax_norm + 4.0 * q0q0 * q1 - _2q0 * ay_norm - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az_norm
        var s2 = 4.0 * q0q0 * q2 + _2q0 * ax_norm + _4q2 * q3q3 - _2q3 * ay_norm - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az_norm
        var s3 = 4.0 * q1q1 * q3 - _2q1 * ax_norm + 4.0 * q2q2 * q3 - _2q2 * ay_norm
        
        // 归一化梯度
        let s_norm = sqrt(s0*s0 + s1*s1 + s2*s2 + s3*s3)
        if s_norm > 0 {
            s0 /= s_norm
            s1 /= s_norm
            s2 /= s_norm
            s3 /= s_norm
        }
        
        // 陀螺仪积分
        let qDot1 = 0.5 * (-q1 * gx - q2 * gy - q3 * gz)
        let qDot2 = 0.5 * (q0 * gx + q2 * gz - q3 * gy)
        let qDot3 = 0.5 * (q0 * gy - q1 * gz + q3 * gx)
        let qDot4 = 0.5 * (q0 * gz + q1 * gy - q2 * gx)
        
        // 融合
        q0 += (qDot1 - beta * s0) * dt
        q1 += (qDot2 - beta * s1) * dt
        q2 += (qDot3 - beta * s2) * dt
        q3 += (qDot4 - beta * s3) * dt
        
        // 归一化四元数
        let q_norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3)
        q0 /= q_norm
        q1 /= q_norm
        q2 /= q_norm
        q3 /= q_norm
        
        quaternion = [q0, q1, q2, q3]
    }
    
    /// 获取线性加速度（去除重力）
    private func getLinearAcceleration(ax: Double, ay: Double, az: Double) -> (x: Double, y: Double, z: Double) {
        let q0 = quaternion[0]
        let q1 = quaternion[1]
        let q2 = quaternion[2]
        let q3 = quaternion[3]
        
        // 重力在传感器坐标系中的表示
        let gx = 2.0 * (q1*q3 - q0*q2) * 9.8
        let gy = 2.0 * (q0*q1 + q2*q3) * 9.8
        let gz = (q0*q0 - q1*q1 - q2*q2 + q3*q3) * 9.8
        
        // 线性加速度 = 总加速度 - 重力
        return (ax - gx, ay - gy, az - gz)
    }
    
    /// 执行预测
    private func predict() {
        // 调试：打印原始数据统计
        let axStats = (min: bufferAx.min() ?? 0, max: bufferAx.max() ?? 0, avg: bufferAx.reduce(0, +) / Double(bufferAx.count))
        let ayStats = (min: bufferAy.min() ?? 0, max: bufferAy.max() ?? 0, avg: bufferAy.reduce(0, +) / Double(bufferAy.count))
        let azStats = (min: bufferAz.min() ?? 0, max: bufferAz.max() ?? 0, avg: bufferAz.reduce(0, +) / Double(bufferAz.count))
        
        print("📊 [调试] 原始加速度统计:")
        print("  Ax: min=\(String(format: "%.3f", axStats.min)), max=\(String(format: "%.3f", axStats.max)), avg=\(String(format: "%.3f", axStats.avg))")
        print("  Ay: min=\(String(format: "%.3f", ayStats.min)), max=\(String(format: "%.3f", ayStats.max)), avg=\(String(format: "%.3f", ayStats.avg))")
        print("  Az: min=\(String(format: "%.3f", azStats.min)), max=\(String(format: "%.3f", azStats.max)), avg=\(String(format: "%.3f", azStats.avg))")
        
        // 使用真正的MFCC特征提取器
        let features = mfccExtractor.extractFeatures(
            ax: bufferAx,
            ay: bufferAy,
            az: bufferAz
        )
        
        // 调试：打印MFCC特征统计
        let featureStats = (min: features.min() ?? 0, max: features.max() ?? 0, avg: features.reduce(0, +) / Float(features.count))
        print("🎵 [调试] MFCC特征统计 (总计\(features.count)维):")
        print("  min=\(String(format: "%.3f", featureStats.min)), max=\(String(format: "%.3f", featureStats.max)), avg=\(String(format: "%.3f", featureStats.avg))")
        print("  前10维: \(features.prefix(10).map { String(format: "%.2f", $0) }.joined(separator: ", "))")
        
        do {
            // 准备输入
            let inputName = model.modelDescription.inputDescriptionsByName.keys.first!
            let inputShape = model.modelDescription.inputDescriptionsByName[inputName]!.multiArrayConstraint!.shape
            
            let inputArray = try MLMultiArray(shape: inputShape as [NSNumber], dataType: .float32)
            
            // 填充特征数据（features已经是Float数组）
            for (i, value) in features.enumerated() {
                if i < inputArray.count {
                    inputArray[i] = NSNumber(value: value)
                }
            }
            
            // 创建输入
            let input = try MLDictionaryFeatureProvider(dictionary: [inputName: inputArray])
            
            // 预测
            let output = try model.prediction(from: input)
            
            // 获取输出
            let outputName = model.modelDescription.outputDescriptionsByName.keys.first!
            if let probArray = output.featureValue(for: outputName)?.multiArrayValue {
                let probability = Double(truncating: probArray[0])
                
                print("🤖 [模型] 输出概率: \(String(format: "%.3f", probability)) (\(String(format: "%.1f%%", probability * 100)))")
                print("🔍 [模型] 输出原始值: \(probArray[0])")
                
                // 更新UI
                DispatchQueue.main.async {
                    self.chewingProbability = probability
                    
                    // 使用滞后比较器（双阈值）确定状态
                    var currentChewingState = self.previousChewingState
                    if !self.previousChewingState && probability > self.upperThreshold {
                        // 从非咀嚼进入咀嚼状态（概率 > 0.6）
                        currentChewingState = true
                        self.chewingActionCount += 1
                        print("👍 [计数] 咀嚼动作 +1! 概率: \(String(format: "%.1f%%", probability * 100)), 总计: \(self.chewingActionCount) 次")
                    } else if self.previousChewingState && probability < self.lowerThreshold {
                        // 从咀嚼退出到非咀嚼状态（概率 < 0.4）
                        currentChewingState = false
                        print("⏹️ [状态] 咀嚼结束, 概率: \(String(format: "%.1f%%", probability * 100))")
                    }
                    // 在0.4-0.6之间保持原状态不变
                    
                    self.isChewing = currentChewingState
                    self.predictionCount += 1
                    
                    // 更新前一状态
                    self.previousChewingState = currentChewingState
                    
                    if self.isChewing {
                        self.chewingDetectedCount += 1
                        self.statusText = String(format: "🍴 咀嚼 (%.1f%%) | 动作: \(self.chewingActionCount) 次", probability * 100)
                    } else {
                        self.statusText = String(format: "⚪ 非咀嚼 (%.1f%%) | 动作: \(self.chewingActionCount) 次", (1 - probability) * 100)
                    }
                }
                
                print("📊 [检测] \(self.statusText)")
            }
            
        } catch {
            print("❌ [检测] 预测失败: \(error)")
            print("❌ [检测] 详细错误: \(error.localizedDescription)")
        }
    }
    
    // 已移除 extractSimplifiedFeatures() - 现在使用 MFCCExtractor
}
